﻿using Abp.Auditing;
using Abp.Authorization;
using Abp.AutoMapper;
using Abp.Collections.Extensions;
using Abp.Events.Bus;
using Abp.Runtime.Session;
using RMM.Core.Entity.Orders;
using RMM.Core.Entity.Shops;
using RMM.Core.Evaluates;
using RMM.Core.Massagistes;
using RMM.Core.Orders;
using RMM.Core.ShopService;
using RMM.Core.UserService;
using RMM.FrameWork;
using RMM.IdGen;
using RMM.Orders.Dtos;
using RMM.Orders.Events;
using RMM.ShopAppService;
using RMM.ShopAppService.Dtos;
using RMM.Shops;
using RMM.Shops.Dtos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RMM.Orders
{
    //[AbpAuthorize]
    public class OrderAppService : IOrderAppService
    {
        private readonly IOrderService _orderService;
        private readonly IOrderItemService _orderItemsService;
        private readonly IMassagistProjectService _massagistProjectService;
        private readonly IShopAppService _shopAppService;
        private readonly IShopProjectService _shopProjectService;
        private readonly IShopService _shopService;
        private readonly IUserService _userservice;
        private readonly OrderNoManager _orderNoManager;
        private readonly IMassagistService _massagistService;
        private readonly IEvaluateService _evaluateService;

        public IAbpSession abpSession { get; set; }
        public IEventBus EventBus { get; set; }

        public OrderAppService(IOrderService orderService
            , IMassagistProjectService massagistProjectService
            , IOrderItemService orderItemsService
            , IUserService userService
            , IShopService shopService
            , IShopAppService shopAppService
            , IShopProjectService shopProjectService
            , OrderNoManager orderNoManager
            , IMassagistService massagistService
            , IEvaluateService evaluateService)
        {
            _orderService = orderService;
            _massagistProjectService = massagistProjectService;
            _orderItemsService = orderItemsService;
            _userservice = userService;
            _shopService = shopService;
            _shopAppService = shopAppService;
            _shopProjectService = shopProjectService;
            _orderNoManager = orderNoManager;
            _massagistService = massagistService;
            _evaluateService = evaluateService;
            abpSession = NullAbpSession.Instance;
            EventBus = NullEventBus.Instance;
        }
        
        public async Task<ResultDto> ModifyOrderStatusAsync(string orderCode, int Status)
        {
            var order = await _orderService.FirstOrDefaultAsync(p => p.OrderCode == orderCode);
            order.Status = Status;
            await _orderService.ModifyAsync(order);
            return ResultDto.Successed;
        }

        public async Task<ResultDto> SetUserOrderReadAsync(long userId,int Status)
        {
            var orders = (await _orderService.GetAll())
                .Where(p => p.UserId == userId && p.Status == Status)
                .ToList();
            orders.ForEach(async p=>
            {
                p.IsRead = true;
                await _orderService.ModifyAsync(p);
            });
            return ResultDto.Successed;
        }

        public async Task<ResultDto> GetUserOrderReadAsync(long userId)
        {
            var orderList = (await _orderService.GetAll())
                .Where(p => p.UserId == userId)
                .GroupBy(p => p.Status)
                .Select(p => new OrderReadDto
                {
                    Status = p.Key,
                    Num = p.Where(x=>!x.IsRead).Count()
                });
            return ResultDto.Success(orderList.ToList());
        }


        public async Task<ResultDto> GetUserOrderAsync(long userId,int orderStatus)
        {
            var orderList = (await _orderService.GetAll())
                .Where(p => p.UserId == userId)
                .WhereIf(orderStatus > 0, p => p.Status == orderStatus);
            var evalList = (await _evaluateService.GetAll())
                .Where(p => p.ObjectType == 1);
            var orderItemList = await _orderItemsService.GetAll();
            var massList = await _massagistService.GetAll();
            var shopList = await _shopService.GetAll();
            var shopProjList = await _shopProjectService.GetAll();

            var result = (from order in orderList
                         join item in orderItemList on order.Id equals item.OrderId
                         join mas in massList on order.MassagistId equals mas.Id
                         join shop in shopList on order.ShopId equals shop.Id
                         join shopProj in shopProjList on shop.ProjectId equals shopProj.Id
                         select new OrderDto
                         {
                             ShopName = shop.ShopName,
                             ProjectName = shopProj.ProjectName,
                             MassagisName = mas.UserName,
                             ServerStartDate = order.ServerStartDate,
                             ServerEndDate = order.ServerEndDate,
                             Num = order.Num,
                             Price = order.Price,
                             OrderCode = order.OrderCode,
                             ShopId = order.ShopId,
                             Status = order.Status,
                             ShopMobile = shop.Mobile
                         }).ToList();

            result.ForEach(p => 
            {
                var s = evalList.Where(x => x.ObjectId == p.ShopId).ToList() ?? new List<Core.Entity.Evaluates.Evaluate>();
                p.Star = s.Sum(x => x.Star) / (s.Count == 0 ? 1 : s.Count);
            });

            return ResultDto.Success(result);
        }


        public async Task<ResultDto> GetOrderAsync(string orderCode)
        {
            var projName = string.Empty;
            var dto = new OrderDto();
            var order = await _orderService.FirstOrDefaultAsync(p => p.OrderCode == orderCode);
            var orderItem = await _orderItemsService.FirstOrDefaultAsync(p => p.OrderId == order.Id);
            var massagist = await _massagistService.FirstOrDefaultAsync(p => p.Id == order.MassagistId);
            var shop = await _shopService.FirstOrDefaultAsync(p => p.Id == order.ShopId);
            projName = (await _massagistProjectService.FirstOrDefaultAsync(p => p.Id == orderItem.ProjectId))?.ProjectName;
            if (string.IsNullOrWhiteSpace(projName))
            {
                projName = (await _shopProjectService.FirstOrDefaultAsync(p => p.Id == orderItem.ProjectId))?.ProjectName;
            }

            dto = order.MapTo<OrderDto>();
            dto.ProjectName = projName;
            dto.ShopName = shop.ShopName;
            dto.ShopMobile = shop.Mobile;
            dto.ShopAddress = shop.Address;
            dto.MassagisName = massagist.UserName;

            return ResultDto.Success(dto);
        }
        

        public async Task<ResultDto> CreateOrderDistanceAsync(CreateOrderDistanceDto dto)
        {
            var order = dto.MapTo<Order>();
            var minute = Convert.ToDecimal( (order.ServerEndDate.Value - order.ServerStartDate.Value).TotalMinutes);

            #region 获取最近的店铺
            var projList = await _shopProjectService.GetAll();
            var shopList = await _shopService.GetAll();
            var list = shopList.AsEnumerable().Join(projList.AsEnumerable(), s => s.Id, p => p.ShopId, (s, p) => new Shop { Id = s.Id, Latitude = s.Latitude, Longitude = s.Longitude }).ToList(); 
            #endregion

            var shop = (await _shopAppService.GetShopByDistanceA(dto.Latitude, dto.Longitude, list)).Data as ShopDto;
            var massagist = (await _massagistService.GetFreeMassagistAsync((int)shop.Id, dto.ServerStartDate, dto.ServerEndDate));
            if (massagist.Count == 0)
            {
                return ResultDto.Fail("亲，当前人数饱满，请稍等下单");
            }
            var MassagistId = massagist.FirstOrDefault().Id;
            var shopProject = await _massagistProjectService.FirstOrDefaultAsync(p => p.MassagistId == MassagistId);

            order.ShopId = shop.Id;
            order.Total = shopProject.Price / shopProject.ProjectTime * minute;
            order.Price = order.Total;
            order.CreatorUserId = abpSession.UserId ?? 0;
            order.CreationTime = DateTime.Now;
            order.OrderCode = _orderNoManager.CreateId();
            order.MakeMobile = dto.MakeMobile;
            order.MakeName = dto.MakeName;
            order.MakeRemake = dto.MakeRemake;
            order.MassagistId = MassagistId;
            order.UserId = abpSession.UserId ?? 0;
            //折扣
            if (CommonHelper.Check(dto.Discount))
            {
                order.Discount = dto.Discount.Value;
                order.Price = order.Price * (order.Discount / 10);
            }
            //优惠券
            if (CommonHelper.Check(dto.Coupon))
            {
                order.Coupon = dto.Coupon.Value;
                order.Price = order.Price - order.Coupon;
            }
            //完成后算人数
            order.Price = order.Price * dto.Num;

            if (order.Price <= 0)
            {
                return ResultDto.Fail("亲，优惠券暂不能使用哦");
            }

            if (order.Num <= 0)
            {
                return ResultDto.Fail("亲，记得选人数哦");
            }

            if (minute <= 0)
            {
                return ResultDto.Fail("亲，记得选时间哦");
            }

            var orderId = await CreateOrderAndGetIdAsync(order);
            var newOrder = await _orderService.FirstOrDefaultAsync(p => p.Id == orderId);

            await EventBus.TriggerAsync(new OrderItemEventData()
            {
                order = order,
                ProjectId = shopProject.Id
            });

            return ResultDto.Success(newOrder.OrderCode);
        }

        public async Task<ResultDto> CreateOrderAsync(CreateOrderDto dto)
        {
            var shopProject = await _shopProjectService.FirstOrDefaultAsync(p => p.Id == dto.ProjectId);
            if (shopProject == null)
            {
                return ResultDto.Fail("项目不存在");
            }


            var order = dto.MapTo<Order>();
            var minute = Convert.ToDecimal((order.ServerEndDate.Value - order.ServerStartDate.Value).TotalMinutes);

            order.ShopId = dto.ShopId;
            order.Total = shopProject.Price / shopProject.ProjectTime * minute;
            order.Price = order.Total;
            order.CreatorUserId = abpSession.UserId ?? 0;
            order.CreationTime = DateTime.Now;
            order.OrderCode = _orderNoManager.CreateId();
            order.MakeMobile = dto.MakeMobile;
            order.MakeName = dto.MakeName;
            order.MakeRemake = dto.MakeRemake;
            order.MassagistId = dto.MassagistId;
            order.UserId = abpSession.UserId ?? 0;
            //折扣
            if (CommonHelper.Check(dto.Discount))
            {
                order.Discount = dto.Discount.Value;
                order.Price = order.Price * (order.Discount / 10);
            }
            //优惠券
            if (CommonHelper.Check(dto.Coupon))
            {
                order.Coupon = dto.Coupon.Value;
                order.Price = order.Price - order.Coupon;
            }
            //完成后算人数
            order.Price = order.Price * dto.Num;

            if (order.Num <= 0)
            {
                return ResultDto.Fail("亲，记得选人数哦");
            }

            if (minute <= 0)
            {
                return ResultDto.Fail("亲，记得选时间哦");
            }

            if (order.Price <= 0)
            {
                return ResultDto.Fail("亲，优惠券暂不能使用哦");
            }

            var orderId = await CreateOrderAndGetIdAsync(order);
            var neworder = await _orderService.FirstOrDefaultAsync(p => p.Id == orderId);

            await EventBus.TriggerAsync(new OrderItemEventData()
            {
                order = order,
                ProjectId = dto.ProjectId
            });
            
            return ResultDto.Success(neworder);
        }


        public async Task<ResultDto> CompleteOrderAsync(string orderCode, int status)
        {
            var order = await _orderService.FirstOrDefaultAsync(p => p.OrderCode == orderCode);
            if (order == null)
            {
                return ResultDto.Fail("订单不存在，请检查订单号");
            }

            if (status != 10 || status != 3)
            {
                return ResultDto.Fail("状态错误");
            }

            await _orderService.ModifyAsync(order.Id, (p) =>
             {
                 p.Status = 3;
                 return Task.FromResult(p);
             });
            return ResultDto.Successed;
        }
        
        private async Task<long> CreateOrderAndGetIdAsync(Order order)
        {
            var result = await _orderService.CreateAndGetIdAsync(order);
            return result.EntityId.Value;
        }
    }
}
